package kvraft

import (
	"6.824/labrpc"
	"fmt"
	"io"
	"log"
	"os"
	"sync"
)
import "crypto/rand"
import "math/big"

type Clerk struct {
	servers []*labrpc.ClientEnd
	// You will have to modify this struct.
	clerkId int64
	cmdId   int64
	//已知的领导者节点
	leaderId int
	mu       sync.Mutex
	logger   *log.Logger
}

func nrand() int64 {
	max := big.NewInt(int64(1) << 62)
	bigx, _ := rand.Int(rand.Reader, max)
	x := bigx.Int64()
	return x
}

func MakeClerk(servers []*labrpc.ClientEnd) *Clerk {
	ck := new(Clerk)
	ck.servers = servers
	// You'll have to add code here.
	ck.clerkId = nrand()
	ck.cmdId = 0
	ck.leaderId = 0
	shortId := ck.clerkId % 10000
	ck.logger = log.New(os.Stdout, fmt.Sprintf("clerk[%04d]: ", shortId), log.LstdFlags|log.Lmicroseconds)
	return ck
}

//
// fetch the current value for a key.
// returns "" if the key does not exist.
// keeps trying forever in the face of all other errors.
//
// you can send an RPC with code like this:
// ok := ck.servers[i].Call("KVServer.Get", &args, &reply)
//
// the types of args and reply (including whether they are pointers)
// must match the declared types of the RPC handler function's
// arguments. and reply must be passed as a pointer.
//
func (ck *Clerk) Get(key string) string {

	// You will have to modify this function.
	ck.mu.Lock()
	defer ck.mu.Unlock()

	ck.cmdId++
	reqId := fmt.Sprintf("(CmdId=%d)", ck.cmdId)

	ck.logger.Printf("发起Get请求 %s，Key=%s，当前已知领导者节点：%d", reqId, key, ck.leaderId)

	args := GetArgs{
		Key:      key,
		ClientId: ck.clerkId,
		CmdId:    ck.cmdId,
	}
	for {
		serverId := ck.leaderId
		reply := GetReply{}
		ok := ck.servers[ck.leaderId].Call("KVServer.Get", &args, &reply)

		ck.logger.Printf("Get请求 %s 发送到节点 %d", reqId, serverId)

		if ok {
			// RPC调用成功
			if reply.Err == ErrWrongLeader {
				// 目标节点不是领导者，更新领导者假设并重试
				ck.logger.Printf("Get请求 %s 失败：节点 %d 不是领导者，切换到下一个节点", reqId, serverId)
				ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
			} else if reply.Err == ErrNoKey {
				// 键不存在（正常业务逻辑）
				ck.logger.Printf("Get请求 %s 完成：Key=%s 不存在", reqId, key)
				return ""
			} else {
				// 成功获取值
				ck.logger.Printf("Get请求 %s 完成：Key=%s，Value=%q", reqId, key, reply.Value)
				return reply.Value
			}
		} else {
			// RPC调用失败（节点可能崩溃）
			ck.logger.Printf("Get请求 %s 失败：节点 %d 无响应，切换到下一个节点", reqId, serverId)
			ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
		}
	}
}

//
// shared by Put and Append.
//
// you can send an RPC with code like this:
// ok := ck.servers[i].Call("KVServer.PutAppend", &args, &reply)
//
// the types of args and reply (including whether they are pointers)
// must match the declared types of the RPC handler function's
// arguments. and reply must be passed as a pointer.
//
func (ck *Clerk) PutAppend(key string, value string, op string) {
	// You will have to modify this function.
	ck.mu.Lock()
	defer ck.mu.Unlock()
	ck.cmdId++
	reqId := fmt.Sprintf("(CmdId=%d)", ck.cmdId)

	ck.logger.Printf("发起%s请求 %s，Key=%s，Value=%q，当前已知领导者节点：%d",
		op, reqId, key, value, ck.leaderId)

	args := PutAppendArgs{
		Key:      key,
		Value:    value,
		Op:       op,
		ClientId: ck.clerkId,
		CmdId:    ck.cmdId,
	}
	for {
		reply := PutAppendReply{}
		serverId := ck.leaderId

		ck.logger.Printf("%s请求 %s 发送到节点 %d", op, reqId, serverId)

		ok := ck.servers[ck.leaderId].Call("KVServer.PutAppend", &args, &reply)
		if ok {
			if reply.Err == ErrWrongLeader {
				ck.logger.Printf("%s请求 %s 失败：节点 %d 不是领导者，切换到下一个节点", op, reqId, serverId)
				ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
			} else {
				// 操作成功（包括重复请求的幂等处理）
				ck.logger.Printf("%s请求 %s 完成：Key=%s 已处理", op, reqId, key)
				return
			}
		} else {
			// 节点无响应，切换到下一个节点
			ck.logger.Printf("%s请求 %s 失败：节点 %d 无响应，切换到下一个节点", op, reqId, serverId)
			ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
		}
	}
}

func (ck *Clerk) Put(key string, value string) {
	ck.PutAppend(key, value, "Put")
}
func (ck *Clerk) Append(key string, value string) {
	ck.PutAppend(key, value, "Append")
}
